using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Drawing.Design;
using System.Runtime.Serialization;
using System.ComponentModel.Design;
using OpenComposite.Workflow.Interfaces;

namespace OpenComposite.Workflow
{
	[Designer(typeof(ParallelSplitDesigner))]
	[ToolboxItem(typeof(ParallelActivityToolboxItem))]
	[ToolboxBitmap(typeof(resfinder), "OpenComposite.Workflow.Resources.toolbox_and.png")]
	public partial class ParallelActivity : DecisionActivity
	{
		public static readonly DependencyProperty CountProperty = DependencyProperty.Register("Count", typeof(int), typeof(ParallelActivity), new PropertyMetadata(2));

		[DescriptionAttribute("Count")]
		[Browsable(true)]
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
		[DefaultValue(2)]
		public int Count
		{
			get { return (int)GetValue(CountProperty); }
			set
			{
				if ( value <= Activities.Count )
					base.SetValue(CountProperty, value);
			}
		}

		private int _currentCounter = 0;

		protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
		{
			//if (Root.RunType == RunType.Analytic) {
			//    return base.Execute(executionContext);
			//} else if (Root.RunType == RunType.RandomDocuments) {
			if ( EnabledActivities.Count == 0 )
				return ActivityExecutionStatus.Closed;

			foreach ( Activity child in EnabledActivities ) {
				child.Closed += new EventHandler<ActivityExecutionStatusChangedEventArgs>(ContinueAt);
				executionContext.ExecuteActivity(child);
			}
			return ActivityExecutionStatus.Executing;
			//} else {
			//    return ActivityExecutionStatus.Closed;
			//}
		}

		void ContinueAt(object sender, ActivityExecutionStatusChangedEventArgs e)
		{
			e.Activity.Closed -= this.ContinueAt;
			_currentCounter++;
			ActivityExecutionContext context = sender as ActivityExecutionContext;

			if ( _currentCounter == Count ) {
				foreach ( ActivityExecutionContext ctx in context.ExecutionContextManager.ExecutionContexts ) {
					if ( ctx.Activity.ExecutionStatus == ActivityExecutionStatus.Executing )
						ctx.CancelActivity(ctx.Activity);
				}

				ActivityExecutionContext subctx = null;
				foreach ( Activity child in Activities ) {
					ActivityExecutionStatus status = child.ExecutionStatus;
					if ( status == ActivityExecutionStatus.Executing ) {
						context.CancelActivity(child);
						child.Closed += ContinueAt;
						subctx = context.ExecutionContextManager.CreateExecutionContext(child);
						context.ExecutionContextManager.CompleteExecutionContext(subctx);
						//subctx.CloseActivity();
					}
				}
				WorkflowHelpers.SecureCloseContext(context);
				//context.CancelActivity(context.Activity);
			} else if ( _currentCounter > Count ) {
				WorkflowHelpers.SecureCloseContext(context);
			}
		}

		protected override ActivityExecutionStatus Cancel(ActivityExecutionContext context)
		{
			bool okToClose = true;

			for ( int n = 0; n < EnabledActivities.Count; n++ ) {
				Activity child = EnabledActivities[n];

				if ( child.ExecutionStatus == ActivityExecutionStatus.Executing ) {
					context.CancelActivity(child);
					okToClose = false;
				} else if ( ( child.ExecutionStatus != ActivityExecutionStatus.Initialized ) && ( child.ExecutionStatus != ActivityExecutionStatus.Closed ) ) {
					okToClose = false;
				}
			}

			if ( context.Activity.ExecutionStatus == ActivityExecutionStatus.Faulting )
				return ActivityExecutionStatus.Faulting;

			if ( okToClose )
				return base.Cancel(context);

			return ActivityExecutionStatus.Canceling;
		}

	}

	public class ParallelSplitDesigner : DecisionDesigner
	{
		private Pen innerSymbolPenM = new Pen(Brushes.Black, 3.0F);
		private SizeF s = SizeF.Empty;

		#region Paint Methods
		protected override void PaintSplit(ActivityDesignerPaintEventArgs e)
		{
			e.Graphics.DrawEllipse(ConnectorPen, bounds);
			e.Graphics.FillEllipse(BackgroundBrush, bounds);

			if ( s == SizeF.Empty )
				s = e.Graphics.MeasureString("AND", TextFont);

			e.Graphics.DrawString("AND",
				TextFont,
				e.DesignerTheme.ForegroundBrush,
				new PointF(WorkflowHelpers.GetCenter(bounds).X - ( s.Width / 2 ),
					WorkflowHelpers.GetCenter(bounds).Y - ( s.Height / 2 )));
		}

		protected override void PaintJoin(ActivityDesignerPaintEventArgs e)
		{
			base.PaintJoin(e);
			//e.Graphics.DrawEllipse(outerSymbolPen, bounds);

			int number = ( this.Activity as ParallelActivity ).Count;
			SizeF s = e.Graphics.MeasureString(number.ToString(), TextFont);

			e.Graphics.DrawString(number.ToString(),
				TextFont,
				e.DesignerTheme.ForegroundBrush,
				new PointF(Bounds.Right - s.Width - 11,
					WorkflowHelpers.GetCenter(Bounds).Y - s.Height - 2));
		}
		#endregion

		protected override void Dispose(bool disposing)
		{
			innerSymbolPenM.Dispose();

			base.Dispose(disposing);
		}

		protected override BranchType BranchType
		{
			get
			{
				return BranchType.Normal;
			}
		}

		protected override void AddBranches(int count)
		{
			if ( ( (ParallelActivity)Activity ).Count == ContainedDesigners.Count && ContainedDesigners.Count != 0 ) {
				Activity.SetValue(ParallelActivity.CountProperty, ContainedDesigners.Count + count);
			}
			base.AddBranches(count);
		}

		public override void RemoveActivities(ReadOnlyCollection<Activity> activitiesToRemove)
		{
			if ( ( (ParallelActivity)Activity ).Count == ContainedDesigners.Count ) {
				Activity.SetValue(ParallelActivity.CountProperty, ContainedDesigners.Count - activitiesToRemove.Count);
			}
			base.RemoveActivities(activitiesToRemove);
		}

		public override bool CanInsertActivities(HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
		{
			if ( activitiesToInsert.Count == 0 )
				return false;

			if ( activitiesToInsert[0] is HorizontalSequenceActivity )
				return true;
			else
				return false;
		}

		protected override Pen ConnectorPen
		{
			get { return new Pen(Color.Purple); }
		}

		protected override LinearGradientBrush BackgroundBrush
		{
			get
			{
				Point start = new Point(bounds.Top + Bounds.Height / 2, bounds.Top);
				Point end = new Point(bounds.Top + Bounds.Height / 2, bounds.Bottom);
				return new LinearGradientBrush(start, end, Color.White, Color.Purple);

			}
		}

		protected override SolidBrush JoinBrush
		{
			get { return (SolidBrush)Brushes.Purple; }
		}
	}

	public class ParallelActivityToolboxItem : ActivityToolboxItem
	{
		public ParallelActivityToolboxItem(Type type)
			: base(type)
		{
			this.DisplayName = "And";
		}

		private ParallelActivityToolboxItem(SerializationInfo info, StreamingContext context)
		{
			Deserialize(info, context);
		}
	}

	[Designer(typeof(HorizontalBranchDesigner))]
	public class HorizontalBranchActivity : HorizontalSequenceActivity
	{
		//#region ITextActivity Members

		//public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(HorizontalBranchActivity), new PropertyMetadata(""));

		//public string Text
		//{
		//    get { return GetValue(TextProperty).ToString(); }
		//    set { SetValue(TextProperty, value); }
		//}

		//#endregion
	}

	public class HorizontalBranchDesigner : HorizontalSequenceDesigner
	{
		protected override Pen ConnectorPen
		{
			get { return new Pen(Color.Purple); }
		}
	}
}
